﻿using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Text;

namespace Dora.Interception
{
    /// <summary>
    /// 构建获取代理的ioc容器
    /// </summary>
    public class InterceptionContainer
    {
        private readonly IServiceCollection _services;

        /// <summary>
        /// 构建获取代理的ioc容器
        /// </summary>
        /// <param name="services">IServiceCollection</param>
        /// <exception cref="ArgumentNullException"></exception>
        public InterceptionContainer(IServiceCollection services)
        {
            _services = services ?? throw new ArgumentNullException(nameof(services));
        }

        /// <summary>
        /// 构建一个IServiceProvider，提供代理服务支持
        /// </summary>
        /// <returns>IServiceProvider</returns>
        public IServiceProvider BuildServiceProvider()
        {
            var serviceProvider = _services.BuildServiceProvider();
            var registrationProvider = serviceProvider.GetRequiredService<IInterceptorRegistrationProvider>();
            var generator = serviceProvider.GetRequiredService<IInterceptableProxyGenerator>();
            var newServices = new ServiceCollection();

            //IServiceCollection继承IList<ServiceDescriptor>
            foreach (var service in _services)
            {
                var list = (IList<ServiceDescriptor>)newServices;

                //不拦截的直接加入容器
                if (!WillIntercept(service))
                {
                    list.Add(service);
                }
                //待拦截的，则构建代理对象的服务描述，并添加容器
                else
                {
                   list.Add(new ServiceDescriptor(service.ServiceType, generator.Generate(service.ServiceType, service.ImplementationType), service.Lifetime));
                }
            }
            return newServices.BuildServiceProvider();

            bool WillIntercept(ServiceDescriptor service)
            {
                //提供服务实例，服务提供工厂或服务实现类型为空的不拦截
                if (service.ImplementationInstance != null || service.ImplementationFactory != null || service.ImplementationType == null)
                {
                    return false;
                }

                return registrationProvider.WillIntercept(service.ImplementationType);
            }
        }
    }
}
